CropAndResize

从输入图像 Tensor 中提取指定区域的切片,并通过双线性插值调整到目标大小。

该算子根据一组归一化坐标框 boxes (格式为 [y1, x1, y2, x2]),从输入图像的对应区域中采样,插值输出到 output_shape 指定的尺寸。

坐标映射

对于第 \(b\) 个框,输出像素 \((h, w)\) 对应的输入浮点坐标 \((y, x)\) 为:

\[y = y_1 \cdot (H_{in} - 1) + h \cdot \frac{(y_2 - y_1) \cdot (H_{in} - 1)}{H_{out} - 1}, \quad \text{当 } H_{out} > 1\]
\[x = x_1 \cdot (W_{in} - 1) + w \cdot \frac{(x_2 - x_1) \cdot (W_{in} - 1)}{W_{out} - 1}, \quad \text{当 } W_{out} > 1\]

\(H_{out} = 1\) 时,\(y = 0.5 \cdot (y_1 + y_2) \cdot (H_{in} - 1)\);当 \(W_{out} = 1\) 时,\(x = 0.5 \cdot (x_1 + x_2) \cdot (W_{in} - 1)\)

边界索引与权重

对浮点坐标 \(out\) 及输入尺寸 \(in\) ,计算整数边界和插值权重:

\[bottom = \max(0, \lfloor out \rfloor)\]
\[top = \min(bottom + 1, in - 1)\]
\[w_{top} = out - bottom\]
\[w_{bottom} = 1 - w_{top}\]

双线性插值

先在水平方向逐行插值,再在垂直方向插值:

\[R_{bottom}[w, c] = I[y_{bottom}[h], x_{left}[w], c] \cdot w_{x\_left}[w] + I[y_{bottom}[h], x_{right}[w], c] \cdot (1 - w_{x\_left}[w])\]
\[R_{top}[w, c] = I[y_{top}[h], x_{left}[w], c] \cdot w_{x\_left}[w] + I[y_{top}[h], x_{right}[w], c] \cdot (1 - w_{x\_left}[w])\]
\[O[b, h, w, c] = R_{bottom}[w, c] \cdot w_{y\_bottom}[h] + R_{top}[w, c] \cdot (1 - w_{y\_bottom}[h])\]

外插值处理

\(y < 0\)\(y > H_{in} - 1\),或 \(x < 0\)\(x > W_{in} - 1\) 时,输出像素值取 extrapolation_value

输入:
  • src - 输入数据的地址。

  • box_idx - boxes的索引,box_idx[i]的值表示第i个框的图像的值。

  • boxes - 第i行表示box_index[i]图像区域的坐标,并且坐标[y1,x1,y2,x2]是归一化后的值。归一化后的坐标值y,映射到图像y*(image_height-1)处,因此归一化后的图像高度范围为[0,1],映射到实际图像高度范围为[0,image_height-1]。我们允许y1>y2,在这种情况下,视为原始图像的上下翻转变换。宽度尺寸的处理类似。坐标取值允许在[0,1]范围之外,在这种情况下,我们使用extrapolation_value外插值进行补齐。

  • param - 算子计算所需参数的结构体。其各成员见下述。

  • extrapolation_value - 外插值。

  • core_mask - 核掩码(仅共享存储版本使用)。

CropAndResizeParameter定义:

 1typedef struct CropAndResizeParameter {
 2    int* input_shape_; // 输入张量形状,4个int,格式为[batch, height, width, channel]
 3    int* output_shape_; // 输出张量形状,4个int,格式为[batch, height, width, channel]
 4    int* x_lefts_; // 水平方向左边界索引,output_shape[2]个int
 5    int* x_rights_; // 水平方向右边界索引,output_shape[2]个int
 6    int* y_tops_; // 垂直方向上边界索引,output_shape[1]个int
 7    int* y_bottoms_; // 垂直方向下边界索引,output_shape[1]个int
 8    void* x_weights_; // 水平方向插值权重,output_shape[2]个float
 9    void* y_weights_; // 垂直方向插值权重,output_shape[1]个float
10    void* line_buffers_; // 双线性插值中间行缓冲,2 * output_shape[2] * input_shape[3] * type_size 字节 * core_num
11} CropAndResizeParameter;
输出:
  • dst - 输出地址。

支持平台:

FT78NE MT7004

备注

  • FT78NE 支持 fp32。

  • MT7004 支持 fp16、fp32。

公式符号与输入参数对照:

公式符号

输入参数/含义

\(I\)

src,输入图像数据

\(O\)

dst,输出数据

\(b\)

框索引,由 box_idx[i] 指定第 \(i\) 个框对应的输入图像编号

\((y_1, x_1, y_2, x_2)\)

boxes[b],第 \(b\) 个框的归一化坐标

\((H_{in}, W_{in}, C_{in})\)

param->input_shape_,输入张量的高度、宽度、通道数

\((H_{out}, W_{out}, C_{out})\)

param->output_shape_,输出张量的高度、宽度、通道数

\(y_{bottom}[h],\; y_{top}[h]\)

param->y_bottoms_[h], param->y_tops_[h],第 \(h\) 行垂直方向的整数边界

\(x_{left}[w],\; x_{right}[w]\)

param->x_lefts_[w], param->x_rights_[w],第 \(w\) 列水平方向的整数边界

\(w_{y\_bottom}[h]\)

param->y_weights_[h],第 \(h\) 行的垂直插值权重

\(w_{x\_left}[w]\)

param->x_weights_[w],第 \(w\) 列的水平插值权重

\(\text{extrapolation_value}\)

extrapolation_value,外插值

共享存储版本:

void fp_crop_and_resize_s(float *src, float *dst, int *box_idx, float *boxes, CropAndResizeParameter *param, float extrapolation_value, int core_mask)
void hp_crop_and_resize_s(float16 *src, float16 *dst, int *box_idx, float *boxes, CropAndResizeParameter *param, float16 extrapolation_value, int core_mask)

C调用示例:

 1// MT7004 示例(共享存储多核,DDR 地址)
 2void TestCropAndResizeSMCFp32(int* input_shape, int* output_shape, float* inp_boxes, int32_t* inp_box_idx, float extrapolation_value, int core_mask) {
 3    int core_id = get_core_id();
 4    int core_num = GetCoreNum(core_mask);
 5    int logic_core_id = GetLogicCoreId(core_mask, core_id);
 6    float* input = (float*)0x88000000;
 7    float* output = (float*)0x89000000;
 8    float* boxes = (float*)0x8A000000;
 9    int* box_idx = (int*)0x8B000000;
10    CropAndResizeParameter* param = (CropAndResizeParameter*)0x8C000000;
11    if (logic_core_id == 0) {
12        memcpy(boxes, inp_boxes, sizeof(float) * output_shape[0] * 4);
13        memcpy(box_idx, inp_box_idx, sizeof(int) * output_shape[0]);
14        param->input_shape_ = (int*)0x8D000000;
15        memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
16        param->output_shape_ = (int*)0x8E000000;
17        memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
18        param->line_buffers_ = (void*)0x8F000000;
19        param->x_lefts_ = (int*)0x90000000;
20        param->x_rights_ = (int*)0x91000000;
21        param->y_bottoms_ = (int*)0x92000000;
22        param->y_tops_ = (int*)0x93000000;
23        param->x_weights_ = (void*)0x94000000;
24        param->y_weights_ = (void*)0x95000000;
25        PrepareCropAndResizeBilinear(param->input_shape_, boxes, param->output_shape_, param->y_bottoms_, param->y_tops_,
26                                        param->x_lefts_, param->x_rights_, param->y_weights_, param->x_weights_); // 做预处理
27    }
28    sys_bar(0, core_num); // 初始化参数完成后进行同步
29    fp_crop_and_resize_s(input, output, box_idx, boxes, param, extrapolation_value, core_mask);
30}
31
32void main(){
33    int input_shape[4] = {1, 4, 4, 4};
34    int output_shape[4] = {1, 8, 8, 4};
35    float boxes[4] = {0, 0, 0.5, 0.5};
36    int box_idx[1] = {0};
37    int core_mask = 0b1111;
38    float extrapolation_value = 0.5;
39    TestCropAndResizeSMCFp32(input_shape, output_shape, boxes, box_idx, extrapolation_value, core_mask);
40}

私有存储版本:

void fp_crop_and_resize_p(float *src, float *dst, int *box_idx, float *boxes, CropAndResizeParameter *param, float extrapolation_value)
void hp_crop_and_resize_p(float16 *src, float16 *dst, int *box_idx, float *boxes, CropAndResizeParameter *param, float16 extrapolation_value)

C调用示例:

 1// MT7004 示例(私有存储单核,AM 地址)
 2void TestCropAndResizeSMCFp32_p(int* input_shape, int* output_shape, float* inp_boxes, int32_t* inp_box_idx, float extrapolation_value) {
 3    float* input = (float*)0x10000000;
 4    float* output = (float*)0x10020000;
 5    float* boxes = (float*)0x10040000;
 6    int* box_idx = (int*)0x10060000;
 7    CropAndResizeParameter* param = (CropAndResizeParameter*)0x10080000;
 8
 9    memcpy(boxes, inp_boxes, sizeof(float) * output_shape[0] * 4);
10    memcpy(box_idx, inp_box_idx, sizeof(int) * output_shape[0]);
11    param->input_shape_ = (int*)0x10090000;
12    memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
13    param->output_shape_ = (int*)0x100A0000;
14    memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
15    param->line_buffers_ = (void*)0x100B0000;
16    param->x_lefts_ = (int*)0x100C0000;
17    param->x_rights_ = (int*)0x100D0000;
18    param->y_bottoms_ = (int*)0x100E0000;
19    param->y_tops_ = (int*)0x100F0000;
20    param->x_weights_ = (void*)0x10100000;
21    param->y_weights_ = (void*)0x10110000;
22    PrepareCropAndResizeBilinear(param->input_shape_, boxes, param->output_shape_, param->y_bottoms_, param->y_tops_,
23                                    param->x_lefts_, param->x_rights_, param->y_weights_, param->x_weights_);
24
25    fp_crop_and_resize_p(input, output, box_idx, boxes, param, extrapolation_value);
26}
27
28void main(){
29    int input_shape[4] = {1, 4, 4, 4};
30    int output_shape[4] = {1, 8, 8, 4};
31    float boxes[4] = {0, 0, 0.5, 0.5};
32    int box_idx[1] = {0};
33    float extrapolation_value = 0.5;
34    TestCropAndResizeSMCFp32_p(input_shape, output_shape, boxes, box_idx, extrapolation_value);
35}